package com.onefish.toolkit.juc;

import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * 高并发场景下的计数器性能测试
 */
public class CounterPerformance {

    public static void main(String[] args) throws InterruptedException {
        int numberOfThreads = 100; // 线程数量
        int numberOfIncrements = 10000000; // 每个线程增加的次数
        int numberOfTests = 3; // 测试次数

        for (int i = 0; i < numberOfTests; i++) {
            System.out.println("Test " + (i + 1) + ":");
            testAtomicLong(numberOfThreads, numberOfIncrements);
            testLongAdder(numberOfThreads, numberOfIncrements);
            System.out.println();
        }
    }

    /**
     * @author liuyan
     * @date 2024-05-23
     * @description 计数器-AtomicLong
     * @throws InterruptedException if interrupted
     */
    private static void testAtomicLong(int numberOfThreads, int numberOfIncrements) throws InterruptedException {
        AtomicLong atomicLong = new AtomicLong(0);
        ExecutorService executor = Executors.newFixedThreadPool(numberOfThreads);

        long startTime = System.currentTimeMillis();
        for (int i = 0; i < numberOfThreads; i++) {
            executor.submit(() -> {
                for (int j = 0; j < numberOfIncrements; j++) {
                    atomicLong.incrementAndGet();
                }
            });
        }
        executor.shutdown();
        executor.awaitTermination(1, TimeUnit.MINUTES);

        long endTime = System.currentTimeMillis();
        System.out.println("AtomicLong: " + (endTime - startTime) + " ms" + " , count: " + atomicLong.get());
    }

    /**
     * @author liuyan
     * @date 2024-05-23
     * @description 计数器-LongAdder
     * @throws InterruptedException if interrupted
     */
    private static void testLongAdder(int numberOfThreads, int numberOfIncrements) throws InterruptedException {
        LongAdder longAdder = new LongAdder();
        ExecutorService executor = Executors.newFixedThreadPool(numberOfThreads);

        long startTime = System.currentTimeMillis();
        for (int i = 0; i < numberOfThreads; i++) {
            executor.submit(() -> {
                for (int j = 0; j < numberOfIncrements; j++) {
                    longAdder.increment();
                }
            });
        }
        //  先销毁线程池，再阻塞主线程，保证主线程在销毁线程池之后再执行后续的操作
        executor.shutdown();
        executor.awaitTermination(1, TimeUnit.MINUTES);

        long endTime = System.currentTimeMillis();
        System.out.println("LongAdder: " + (endTime - startTime) + " ms" + " , count: " + longAdder.sum());
    }
}
